package com.yellow.cloud.security.oauth2.controller;

import com.yellow.cloud.security.autoconfigure.SecurityProperties;
import com.yellow.cloud.security.oauth2.service.AuthService;
import com.yellowframework.cloud.api.security.AuthControllerApi;
import com.yellowframework.cloud.common.constant.Constants;
import com.yellowframework.cloud.common.exception.ExceptionCast;
import com.yellowframework.cloud.common.model.response.CommonCode;
import com.yellowframework.cloud.common.model.response.ResponseResult;
import com.yellowframework.cloud.domain.security.AuthToken;
import com.yellowframework.cloud.domain.security.request.LoginRequest;
import com.yellowframework.cloud.domain.security.response.AuthCode;
import com.yellowframework.cloud.domain.security.response.JwtResult;
import com.yellowframework.cloud.domain.security.response.LoginResult;
import com.yellowframework.cloud.utils.CookieUtils;
import com.yellowframework.cloud.utils.RedisUtils;
import com.yellowframework.cloud.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Objects;

/**
 * @Author zhou
 * @Date 2020/9/24 13:26
 */
@RestController
@RequestMapping("/oauth")
public class AuthController implements AuthControllerApi {

    @Autowired
    private AuthService authService;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 客户端密钥
     */
    @Override
    @PostMapping("/login")
    public LoginResult login(LoginRequest loginRequest) {

        // 校验账号是否输入
        if(loginRequest == null || StringUtils.isEmpty(loginRequest.getUsername())){
            ExceptionCast.cast(AuthCode.AUTH_USERNAME_NONE);
        }

        // 校验密码是否输入
        if(StringUtils.isEmpty(loginRequest.getPassword())){
            ExceptionCast.cast(AuthCode.AUTH_PASSWORD_NONE);
        }

        if(StringUtils.isEmpty(loginRequest.getUuid()) || StringUtils.isEmpty(loginRequest.getCaptcha())){
            ExceptionCast.cast(AuthCode.AUTH_VERIFYCODE_NONE);
        }

        validate(loginRequest.getUuid(), loginRequest.getCaptcha());

        AuthToken authToken = authService.login(loginRequest.getUsername(), loginRequest.getPassword(), SecurityProperties.auth.getClientId(), SecurityProperties.auth.getClientSecret());

        //访问token
        String access_token = authToken.getAccess_token();

        //将访问令牌存储到cookie
        saveCookie(access_token);

        return LoginResult.success(access_token);
    }

    /**
     * 将令牌保存到cookie
     * @param token 用户身份令牌
     * @return void
     * @author zhouhao
     * @date  2020/9/24 14:06
     */
    private void saveCookie(String token){

        HttpServletResponse response = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();

        assert response != null;

        // 添加cookie 认证令牌，最后一个参数设置为false，表示允许浏览器获取
        CookieUtils.addCookie(response, SecurityProperties.auth.getCookieDomain(), "/", "uid", token, SecurityProperties.auth.getCookieMaxAge(), false);
    }

    /**
     * 清除cookie中的token
     * @param token 用户身份令牌
     * @return void
     * @author zhouhao
     * @date  2020/9/24 14:06
     */
    private void clearCookie(String token){

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();

        // 清除cookie
        CookieUtils.addCookie(response, SecurityProperties.auth.getCookieDomain(), "/", "uid", token, 0, false);
    }

    @Override
    @PostMapping("/logout")
    public ResponseResult logout() {

        //取出身份令牌
        String uid = getTokenFormCookie();

        //删除redis中token
        authService.delToken(uid);

        //清除cookie
        clearCookie(uid);

        return ResponseResult.success();
    }

    @Override
    @GetMapping("/userjwt")
    public JwtResult userjwt() {

        // 取出cookie中的用户身份令牌
        String uid = this.getTokenFormCookie();
        if(StringUtils.isEmpty(uid)){
            ExceptionCast.cast(CommonCode.TOKEN_EXPIRED);
        }

        // 通过身份令牌获取redis中的jwt长令牌
        AuthToken userToken = authService.getUserToken(uid);
        if(userToken == null){
            //清除cookie
            clearCookie(uid);
            ExceptionCast.cast(CommonCode.TOKEN_EXPIRED);
        }

        // 把jwt返回
        return JwtResult.success(userToken.getJwt_token());
    }

    /**
     * 从cookie中读取用户访问令牌
     * @author Hao.
     * @date 2020/10/21 18:46
     * @param
     * @return java.lang.String
     */
    private String getTokenFormCookie(){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Map<String, String> cookieMap = CookieUtils.readCookie(request, "uid");
        String access_token = cookieMap.get("uid");
        return access_token;
    }

    public void validate(String uuid, String captcha) {
        final String key = Constants.CAPTCHA_CODE_KEY + uuid;
        if(!redisUtils.exists(key) || !redisUtils.get(key).equalsIgnoreCase(captcha)){
            redisUtils.remove(key);
            ExceptionCast.cast(CommonCode.VERIFICATION_CODE_ERROR);
        }
    }

}
